package com.tuhui.listener;

import org.apache.commons.io.FileUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.util.StringUtils;

import java.io.*;
import java.net.SocketException;
import java.util.*;

public class FtpUtil {

    //ftp地址
    public static String ftpHost = null;
    //ftp用户
    public static String ftpUserName = null;
    //ftp密码
    public static String ftpPassword = null;
    //ftp端口
    public static Integer ftpPort = null;
    //上传到ftp的地址
    public static String ftpPath = null;
    //监听文件变化的地址
    public static String listenerPath = null;
    //第一次监听是否上传所有文件
    public static Boolean allUpload = false;
    //默认半个小时
    public static Integer timeMin = 30;

    /**
     * 获取FTPClient对象
     *
     * @param ftpHost     FTP主机服务器
     * @param ftpPassword FTP 登录密码
     * @param ftpUserName FTP登录用户名
     * @param ftpPort     FTP端口 默认为21
     * @return
     */
    public static FTPClient getFTPClient(String ftpHost, String ftpUserName,
                                         String ftpPassword, int ftpPort) {
        FTPClient ftpClient = new FTPClient();
        try {
            ftpClient = new FTPClient();
            ftpClient.connect(ftpHost, ftpPort);// 连接FTP服务器
            ftpClient.login(ftpUserName, ftpPassword);// 登陆FTP服务器
            if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
                System.out.println("未连接到FTP，用户名或密码错误。");
                ftpClient.disconnect();
            } else {
                System.out.println("FTP连接成功。");
            }
        } catch (SocketException e) {
            e.printStackTrace();
            System.out.println("FTP的IP地址可能错误，请正确配置。");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("FTP的端口错误,请正确配置。");
        }
        return ftpClient;
    }

    /*
     * 从FTP服务器下载文件
     *
     * @param ftpHost FTP IP地址
     * @param ftpUserName FTP 用户名
     * @param ftpPassword FTP用户名密码
     * @param ftpPort FTP端口
     * @param ftpPath FTP服务器中文件所在路径 格式： ftptest/aa
     * @param localPath 下载到本地的位置 格式：H:/download
     * @param fileName 文件名称
     */
    public static void downloadFtpFile(String ftpHost, String ftpUserName,
                                       String ftpPassword, int ftpPort, String ftpPath, String localPath,
                                       String fileName) {

        FTPClient ftpClient = null;
        try {
            ftpClient = getFTPClient(ftpHost, ftpUserName, ftpPassword, ftpPort);
            ftpClient.setControlEncoding("UTF-8"); // 中文支持
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            ftpClient.enterLocalPassiveMode();
            ftpClient.changeWorkingDirectory(ftpPath);
            File localFile = new File(localPath + File.separatorChar + fileName);
            OutputStream os = new FileOutputStream(localFile);
            ftpClient.retrieveFile(fileName, os);
            os.close();
            ftpClient.logout();
        } catch (FileNotFoundException e) {
            System.out.println("没有找到" + ftpPath + "文件");
            e.printStackTrace();
        } catch (SocketException e) {
            System.out.println("连接FTP失败.");
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("文件读取错误。");
            e.printStackTrace();
        }

    }

    /**
     * Description: 向FTP服务器上传文件
     * @param ftpHost FTP服务器hostname
     * @param ftpUserName 账号
     * @param ftpPassword 密码
     * @param ftpPort 端口
     * @param ftpPath  FTP服务器中文件所在路径 格式： ftptest/aa
     * @param fileName ftp文件名称
     * @param input 文件流
     * @return 成功返回true，否则返回false
     */
    public static boolean uploadFile(String ftpHost, String ftpUserName,
                                     String ftpPassword, int ftpPort, String ftpPath,
                                     String fileName,InputStream input) {
        boolean success = false;
        FTPClient  ftpClient = null;
        try {
            int reply;
            ftpClient = getFTPClient(ftpHost, ftpUserName, ftpPassword, ftpPort);
            reply = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftpClient.disconnect();
                return success;
            }
            ftpClient.setBufferSize(1024);//设置上传缓存大小
            ftpClient.setControlEncoding("UTF-8"); // 中文支持
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);//设置文件类型
            ftpClient.enterLocalPassiveMode();
            //判断文件是否存在
            StringTokenizer strPath = new StringTokenizer(ftpPath,"/");
            String newPath = "";
            boolean ftpFileStatus = true;
            while (strPath.hasMoreTokens()){
                String nexPath = strPath.nextToken();
                newPath = newPath +"/"+ nexPath;
                if(!existDirectory(ftpClient, nexPath)){
                    Boolean createFlase = createDirectory(ftpClient,nexPath);
                    if(!createFlase){
                        System.out.println("crateWoke error 创建目录"+nexPath+"失败");
                        ftpFileStatus =false;
                        break;
                    }else{
                        System.out.println("crateWoke success 创建目录"+nexPath+"成功");
                        ftpFileStatus = checkChangeWorkingDirectory(ftpClient,newPath);
                        if(!ftpFileStatus){
                            break;
                        }
                    }
                }else{
                    ftpFileStatus = checkChangeWorkingDirectory(ftpClient,newPath);
                    if(!ftpFileStatus){
                        break;
                    }
                }
            }
            if(!ftpFileStatus){
                //writFile(ftpPath+"/"+fileName);
                return success;
            }
            Boolean ftpUploadStatus = ftpClient.storeFile(fileName, input);
            if(ftpUploadStatus){
                System.out.println("upload success:"+ftpPath+"/"+fileName);
            }else {
                System.out.println("upload fail:"+ftpPath+"/"+fileName);
                //writFile(ftpPath+"/"+fileName);
            }
            input.close();
            ftpClient.logout();
            success = true;
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("uploadFile 方法调用失败!");
            return success;
        } finally {
            if (ftpClient.isConnected()) {
                try {
                    ftpClient.disconnect();
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                    return success;
                }
            }
        }
        return success;
    }

    /**
     * ftp目录切换
     * @return
     */
    public  static Boolean checkChangeWorkingDirectory(FTPClient ftpClient,String ftpPath){
        Boolean changeWork = null;
        try {
            changeWork = ftpClient.changeWorkingDirectory(ftpPath);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("changeWork error 切换目录"+ftpPath+"失败:"+e.getMessage());
            return false;
        }
        if(!changeWork){
            System.out.println("changeWork error 切换目录"+ftpPath+"失败");
            return false;
        }
        System.out.println("changeWork success 切换目录"+ftpPath+"成功");
        return true;
    }
    /**
     * 检查目录在服务器上是否存在 true：存在  false：不存在
     * @param path
     * @return
     * @throws IOException
     */
    public static boolean existDirectory(FTPClient ftpClient,String path) throws IOException {
        boolean flag = false;
        FTPFile[] ftpFileArr = ftpClient.listFiles();
        for (FTPFile ftpFile : ftpFileArr) {
            if (ftpFile.isDirectory()
                    && ftpFile.getName().equalsIgnoreCase(path)) {
                flag = true;
                break;
            }
        }
        return flag;
    }


    /**
     * 在服务器上创建目录
     * @param pathName
     * @return
     * @throws IOException
     */
    public static boolean createDirectory(FTPClient ftpClient,String pathName) throws IOException {
        return ftpClient.makeDirectory(pathName);
    }

    /**
     * 读取配置文件的信息
     *
     */
    public static  void  setFtp() {
        //上传一个文件
        InputStreamReader reader = null;
        //检查是否是一个文件
        //checkFile(path);
        Properties props = new Properties();
        try {
            //System.out.println("配置文件的地址："+path);
            reader = new InputStreamReader(new FileInputStream("ftp.properties"), "utf-8");
            props.load(reader); //load个人建议还是用Reader来读，因为reader体系中有个InputStreamReader可以指定编码
            FtpUtil.ftpHost = props.getProperty("ftpHost");
            FtpUtil.ftpUserName = props.getProperty("ftpUserName");
            FtpUtil.ftpPassword = props.getProperty("ftpPassword");
            FtpUtil.ftpPort = Integer.parseInt(props.getProperty("ftpPort"));
            FtpUtil.ftpPath = props.getProperty("ftpPath");
            FtpUtil.listenerPath = props.getProperty("listenerPath");
            Integer timeMin = Integer.parseInt(props.getProperty("timeMin"));
            String allUpload =props.getProperty("allUpload");
            if(!StringUtils.isEmpty(allUpload)){
                FtpUtil.allUpload = Boolean.parseBoolean(allUpload);
            }
            if(!StringUtils.isEmpty(timeMin)){
                FtpUtil.timeMin = timeMin;
            }

            System.out.println("ftpHost:" + ftpHost);
            System.out.println("ftpUserName:" + ftpUserName);
            System.out.println("ftpPassword:" + ftpPassword);
            System.out.println("ftpPort:" + ftpPort);
            System.out.println("ftpPath:" + ftpPath);
            System.out.println("listenerPath:" + listenerPath);
            System.out.println("allUpload:" + FtpUtil.allUpload);
            System.out.println("timeMin:" + FtpUtil.timeMin);
            //调用服务的监听
            ListenerFile.addListener(FtpUtil.listenerPath);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("读取配置文件失败！");
        } finally {
            try {
                reader.close();
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println(e);
            }
        }
    }

    /**
     * 检查配置 文件是否正确
     * @param path
     * @return
     */
    public static String checkFile(String path){
        File file = new File(path);
        if(!file.exists() || !file.isFile()){
            System.out.println("请传递一个正确的properties文件配置的地址");
            Scanner scan = new Scanner(System.in);
            path = scan.nextLine();
            System.out.println("输入的地址是："+path);
            checkFile(path);
        }
        return path;
    }

    /**
     * 把上传错误的文件地址信息记录下来
     * @param oldFilePath
     */
    public static void  writFile(String oldFilePath){
        //ftp文件保持不变
        String filePath[] = oldFilePath.split("\\\\");
        String ftpPath[] = FtpUtil.listenerPath.split("\\\\");
        //String ftpPath[] = "D:\\aa".split("\\\\");
        String uploadFtpPath = "";
        if(filePath.length!=ftpPath.length){
            for(int i=ftpPath.length;i<filePath.length;i++){
                uploadFtpPath+="/"+filePath[i];
            }
        }
         File errorFile = new File("error/"+uploadFtpPath);
         File oldFile = new File(oldFilePath);
        try {
           if(!errorFile.getParentFile().exists()){
               errorFile.getParentFile().mkdirs();
           }
           if(!errorFile.exists()){
               errorFile.createNewFile();
           }
            System.out.println("writ error File path "+errorFile.getAbsolutePath());
            FileUtils.copyFile(oldFile,errorFile);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("writFile fail"+e.getMessage());
        }
    }

    /**
     * 读取错误文件的信息
     */
    public static List<String>  redFile(){
        ArrayList<String> arrayList = new ArrayList<>();
        try {
            FileReader fr = new FileReader("error.txt");
            BufferedReader bf = new BufferedReader(fr);
            String str;
            // 按行读取字符串
            while ((str = bf.readLine()) != null) {
                arrayList.add(str);
            }
            bf.close();
            fr.close();
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("读取文件失败====");
        }
        // 对ArrayList中存储的字符串进行处理
        arrayList.forEach(path->{
            System.out.println("读取错误文件的信息:"+path);
        });
        return arrayList;
    }

    /**
     * 删除文件
     */
    public  static void deleteFile(File file){
      file.delete();
        try {
            if(ListenerFile.getFiles(file.getParent()).size()<=0){
                file.getParentFile().delete();
                if(file.getParentFile().getParentFile()!=null){
                    deleteFile(file.getParentFile().getParentFile());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("删除文件时错误："+e.getMessage());
        }
    }

    public static void main(String[] args) throws Exception {
      /*  ArrayList<File> files = null;
        try {
            files = ListenerFile.getFiles("error");
        } catch (Exception e) {
            System.out.println("读取文件失败："+e.getMessage());
            e.printStackTrace();
        }
        //进行文件上传
        if(files!=null && files.size()>0){
            files.forEach(file->{
               deleteFile(file);
            });
        }*/
     // deleteFile(new File("error\\20190510\\23\\cc.jpg"));
//        System.out.println(file.getAbsoluteFile());
      // writFile("d:\\aa\\20190510\\23\\cc.jpg");
       /* String ftpHost = "192.168.11.161";
        String ftpUserName = "admin";
        String ftpPassword = "admin";
        int ftpPort = 21;
        String ftpPath = "/aa";
        String localPath = "F:\\aa\\aa.jpg";
        String fileName = "cc.jpg";
        Properties props = new Properties();

        //上传一个文件
        InputStreamReader reader  = null;
        try{
            reader =  new InputStreamReader(new FileInputStream("E:\\work\\ftp.properties"),"utf-8");
            props.load(reader); //load个人建议还是用Reader来读，因为reader体系中有个InputStreamReader可以指定编码
            FileInputStream in=new FileInputStream(new File(localPath));
            boolean test = FtpUtil.uploadFile(ftpHost, ftpUserName, ftpPassword, ftpPort, ftpPath, fileName,in);
            System.out.println("ftpHost:"+props.getProperty("ftpHost"));
        } catch (Exception e){
            e.printStackTrace();
        }finally {
            try{
                reader.close();
            }catch (Exception e){
                System.out.println(e);
            }

        }*/

        //在FTP服务器上生成一个文件，并将一个字符串写入到该文件中
//        try {
//            InputStream input = new ByteArrayInputStream("test ftp jyf".getBytes("GBK"));
//            boolean flag = FtpUtil.uploadFile(ftpHost, ftpUserName, ftpPassword, ftpPort, ftpPath, fileName,input);;
//            System.out.println(flag);
//        } catch (UnsupportedEncodingException e) {
//            e.printStackTrace();
//        }

        //下载一个文件
//        FtpUtil.downloadFtpFile(ftpHost, ftpUserName, ftpPassword, ftpPort, ftpPath, localPath, fileName);
    }

}
